defmodule SockWorkstation.CoopTopSup do
  use DynamicSupervisor

  # require Logger
  @name __MODULE__
  def start_link(init_arg) do
    DynamicSupervisor.start_link(@name, init_arg, name: @name)
  end

  @impl true
  def init(_init_arg) do
    DynamicSupervisor.init(strategy: :one_for_one)
  end
end

defmodule SockWorkstation.CoopSecSup do
  use DynamicSupervisor

  @name __MODULE__

  def start_link(session_id) do
    DynamicSupervisor.start_link(@name, session_id, name: via_tuple(session_id, "coop_dynsup"))
  end

  @impl true
  def init(_sesion_id) do
    DynamicSupervisor.init(strategy: :one_for_one)
  end

  defp via_tuple(session_id, type) do
    {:via, Registry, {SockWorkstation.SessionRegistry, {session_id, type}}}
  end
end

defmodule SockWorkstation.SessionMgr do
  require Logger
  alias SockWorkstation.{CoopTopSup, CoopSecSup, SessionAgent}

  alias SockWorkstation.{
    SockCoopClient,
    # SockTTSClient,
    # SockASRClient,
    # GrpcLLMClient,
    GrpcVADClient,
    CoopMgrGen,
    CodecNifGen,
    TTSHelperGen,
    ASRHelperGen,
    # OpusDecoderGen,
    PcmEncoderGen,
    FrameHelperGen,
    # PingPongGen
    # SockVOTTSClient,
    # SockVOASRClient
  }

  def start_session(session_id) do
    # 启动二级动态监督者
    # {:ok, second_level_supervisor} =
    case DynamicSupervisor.start_child(CoopTopSup, {CoopSecSup, session_id}) do
      {:ok, second_level_supervisor} ->
        children_specs = [
          {CoopMgrGen, :start_link, [session_id]},
          {CodecNifGen, :start_link, [session_id]},
          # {OpusDecoderGen, :start_link, [session_id]},
          {PcmEncoderGen, :start_link, [session_id]},
          {FrameHelperGen, :start_link, [session_id]},
          {TTSHelperGen, :start_link, [session_id]},
          {ASRHelperGen, :start_link, [session_id]},
          {SockCoopClient, :start_link, [session_id]},
          {GrpcVADClient, :start_link, [session_id]},
          # {PingPongGen, :start_link, [session_id]},

        ]

        children_specs
        |> Enum.each(fn {module, start_function, args} ->
          child_spec = %{
            id: make_ref(),
            start: {module, start_function, args}
          }

          case DynamicSupervisor.start_child(second_level_supervisor, child_spec) do
            {:ok, _pid} ->
              # Process.link(second_level_supervisor)
              # Process.link(pid)
              :ok

            {:error, {:already_started, _pid}} ->
              # CoopMgrGen.add_to_pcm_pid(session_id, pid)
              :ok

            {:error, reason} ->
              Logger.warning(
                "Failed to start child: #{inspect(module)} - Reason: #{inspect(reason)}",
                tag: "start_session"
              )

              # IO.puts("Failed to start child: #{inspect(module)} - Reason: #{inspect(reason)}")
          end
        end)

        SessionAgent.save_supervisor(session_id, second_level_supervisor)
        {:ok, second_level_supervisor}

      {:error, {:already_started, second_level_supervisor}} ->
        {:ok, second_level_supervisor}

      _ ->
        {:error, "Failed to start CoopSecSupervisor"}
    end
  end

  # def dyn_coop_client(session_id) do
  #   # 生成唯一的 ID
  #   unique_id = make_ref()

  #   # child_spec = %{
  #   #   id: {:worker, unique_id},
  #   #   start: {SockCoopClient, :start_link, [session_id]},
  #   #   restart: :temporary
  #   # }

  #   child_spec = %{
  #     id: unique_id,
  #     start: {SockCoopClient, :start_link, [session_id]}
  #   }

  #   with {:error, {:already_started, second_level_supervisor}} <-
  #          DynamicSupervisor.start_child(CoopTopSup, {CoopSecSup, session_id}) do
  #     case DynamicSupervisor.start_child(second_level_supervisor, child_spec) do
  #       {:ok, _pid} ->
  #         # 链接子进程到二级监督者
  #         # Process.link(second_level_supervisor)
  #         # Process.link(pid)
  #         SessionAgent.save_supervisor(session_id, second_level_supervisor)
  #         {:ok, second_level_supervisor}

  #       {:error, reason} ->
  #         Logger.warning(
  #           "Failed to start child: SockCoopClient - Reason: #{inspect(reason)}",
  #           tag: "dyn_coop_client"
  #         )

  #         {:error, reason}
  #     end

  #   end
  # end

  def get_second_level_supervisor(session_id) do
    # 从Agent中获取二级监督者的PID
    # SessionAgent.get_supervisor(session_id)
    case SessionAgent.get_supervisor(session_id) do
      nil -> {:error, :supervisor_not_found}
      pid -> {:ok, pid}
    end
  end

  # 获取二级动态监督者的所有子进程PID
  def get_all_child_pids(session_id) do
    case get_second_level_supervisor(session_id) do
      {:ok, second_level_supervisor} ->
        # 获取所有子进程的信息
        children = DynamicSupervisor.which_children(second_level_supervisor) |> Enum.reverse()
        # 提取子进程的PID
        pids = Enum.map(children, fn {_id, pid, _type, _module} -> pid end)
        {:ok, pids}

      {:error, reason} ->
        {:error, reason}
    end
  end

  def get_all_child_pidinfos(session_id) do
    case get_second_level_supervisor(session_id) do
      {:ok, second_level_supervisor} ->
        # 获取所有子进程的信息
        children = DynamicSupervisor.which_children(second_level_supervisor) |> Enum.reverse()
        # 提取子进程的PID
        pidinfos = Enum.map(children, fn {_id, pid, _type, [module]} -> {pid, module} end)
        {:ok, pidinfos}

      {:error, reason} ->
        {:error, reason}
    end
  end

  def stop_session(session_id) do
    # 获取二级监督者的PID
    case get_second_level_supervisor(session_id) do
      {:ok, second_level_supervisor} ->
        # 停止二级监督者及其所有子进程
        children = DynamicSupervisor.which_children(second_level_supervisor)

        # 提取子进程的PID并按相反顺序停止它们
        children
        |> Enum.reverse()
        |> Enum.each(fn {_id, pid, _type, _modules} ->
          # DynamicSupervisor.terminate_child(second_level_supervisor, pid)
          case DynamicSupervisor.terminate_child(second_level_supervisor, pid) do
            :ok ->
              :ok

            {:error, reason} ->
              Logger.warning(
                "Failed to stop child process: #{inspect(pid)} - Reason: #{inspect(reason)}",
                tag: "stop_session"
              )
          end
        end)

        DynamicSupervisor.terminate_child(SockWorkstation.CoopTopSup, second_level_supervisor)
        SessionAgent.remove_supervisor(session_id)

      {:error, :supervisor_not_found} ->
        :ok

      {:error, reason} ->
        Logger.warning("Failed to stop second level supervisor: #{inspect(reason)}",
          tag: "stop_session"
        )
    end
  end
end

defmodule SockWorkstation.SessionAgent do
  use Agent

  @name __MODULE__
  def start_link(_) do
    Agent.start_link(fn -> %{} end, name: @name)
  end

  def save_supervisor(session_id, pid) do
    Agent.update(@name, &Map.put(&1, session_id, pid))
  end

  def get_supervisor(session_id) do
    Agent.get(@name, &Map.get(&1, session_id))
  end

  def remove_supervisor(session_id) do
    Agent.update(@name, &Map.delete(&1, session_id))
  end
end

# CoopSecSup.super_coop_mgr(session_id),
# CoopSecSup.super_pcm_encode(session_id),
# CoopSecSup.super_nif_codec(session_id),
# CoopSecSup.super_asr_helper(session_id),
# CoopSecSup.super_tts_helper(session_id),
# CoopSecSup.super_vad_client(session_id),
# CoopSecSup.super_frame_queue(session_id)
